package fun

import (
	"os"
	"path/filepath"
	"reflect"
	"time"
)

/*
【名称:】获取导入包的绝对路径
【参数:】包路由(string)，版本号
【返回:】包的绝对地址
【备注:】
*/
func GetImportPackagePath(packagePath string, version string) string {
	path := filepath.Join(os.Getenv("GOPATH"), "pkg", "mod")
	arr := Explode("/", packagePath)

	for _, v := range arr {
		path = filepath.Join(path, v)
	}
	path += "@" + version

	return path
}

/*
// @title: 魔法函数（调用某结构体的方法）
// @param: obj（结构体对象）
// @param: funName（方法名）
// @param: args（方法中要传的N个参数）
// @return:
// @description: 是一个通用函数，用于反射性地调用任何对象上的方法。
// @date: 2022/7/3 21:40
*/
func CallFun(obj interface{}, funName string, args ...interface{}) []reflect.Value {
	inputs := make([]reflect.Value, len(args))
	for i, _ := range args {
		inputs[i] = reflect.ValueOf(args[i])
	}
	return reflect.ValueOf(obj).MethodByName(funName).Call(inputs)
}

/*
【名称:】获取环境变量值
【参数:】
【返回:】
【备注:】
*/
func GetEnv(key string) (string, bool) {
	return os.LookupEnv(key)
}

/*
【名称:】设置环境变量值
【参数:】
【返回:】
【备注:】
*/
func SetEnv(key string, val string) error {
	return os.Setenv(key, val)
}

type _interface interface {
	DeepCopy() interface{}
}

/*
【名称:】深拷贝
【参数:】
【返回:】
【备注:】
*/
func Copy(src interface{}) interface{} {
	if src == nil {
		return nil
	}

	// Make the interface a reflect.Value
	original := reflect.ValueOf(src)

	// Make a copy of the same type as the original.
	cpy := reflect.New(original.Type()).Elem()

	// Recursively copy the original.
	copyRecursive(original, cpy)

	// Return the copy as an interface.
	return cpy.Interface()
}

// copyRecursive does the actual copying of the interface. It currently has
// limited support for what it can handle. Add as needed.
func copyRecursive(original, cpy reflect.Value) {
	// check for implement deepcopy.Interface
	if original.CanInterface() {
		if copier, ok := original.Interface().(_interface); ok {
			cpy.Set(reflect.ValueOf(copier.DeepCopy()))
			return
		}
	}

	// handle according to original's Kind
	switch original.Kind() {
	case reflect.Ptr:
		// Get the actual value being pointed to.
		originalValue := original.Elem()

		// if  it isn't valid, return.
		if !originalValue.IsValid() {
			return
		}
		cpy.Set(reflect.New(originalValue.Type()))
		copyRecursive(originalValue, cpy.Elem())

	case reflect.Interface:
		// If this is a nil, don't do anything
		if original.IsNil() {
			return
		}
		// Get the value for the interface, not the pointer.
		originalValue := original.Elem()

		// Get the value by calling Elem().
		copyValue := reflect.New(originalValue.Type()).Elem()
		copyRecursive(originalValue, copyValue)
		cpy.Set(copyValue)

	case reflect.Struct:
		t, ok := original.Interface().(time.Time)
		if ok {
			cpy.Set(reflect.ValueOf(t))
			return
		}
		// Go through each field of the struct and copy it.
		for i := 0; i < original.NumField(); i++ {
			// The Type's StructField for a given field is checked to see if StructField.PkgPath
			// is set to determine if the field is exported or not because CanSet() returns false
			// for settable fields.  I'm not sure why.  -mohae
			if original.Type().Field(i).PkgPath != "" {
				continue
			}
			copyRecursive(original.Field(i), cpy.Field(i))
		}

	case reflect.Slice:
		if original.IsNil() {
			return
		}
		// Make a new slice and copy each element.
		cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
		for i := 0; i < original.Len(); i++ {
			copyRecursive(original.Index(i), cpy.Index(i))
		}

	case reflect.Map:
		if original.IsNil() {
			return
		}
		cpy.Set(reflect.MakeMap(original.Type()))
		for _, key := range original.MapKeys() {
			originalValue := original.MapIndex(key)
			copyValue := reflect.New(originalValue.Type()).Elem()
			copyRecursive(originalValue, copyValue)
			copyKey := Copy(key.Interface())
			cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue)
		}

	default:
		cpy.Set(original)
	}
}

/*
【名称:】获取变量类型
【参数:】变量(interface)
【返回:】类型名(string)
【备注:】
*/
func GetType(variable interface{}) string {
	return reflect.TypeOf(variable).Kind().String()
}
